DevNation / 14th of April - 2014
Charles Moulliard
Architect, Engineer & Committer
Agricultural Engineer & Zoologist
19 years of experience in IT world development
Project manager in Bank, Financial, Telco world
Specialized in new technologies Web & Integration
Architect/Engineer @Red Hat
Committer : Apache ServiceMix, Karaf (PMC), Camel (PMC), Fabric8, Drools, Hawtio, Asciidoctor
Twitter : http://twitter.com/cmoulliard | |
LinkedIn : http://www.linkedin.com/in/charlesmoulliard | |
Blog : http://cmoulliard.github.io | |
Slideshare : http://www.slideshare.net/cmoulliard |
Introduction
Social Media Hype
Use cases covered
Integration & Camel
Technology
What JBoss Fuse can offer
Conclusion
|
| |
|
Introduction
Social Media Hype
Use cases covered
Integration & Camel
Technology
What JBoss Fuse can offer
Conclusion
Why To create content that attracts attention & encourages readers to share it with their social networks
Introduction
Social Media Hype
Use cases covered
Integration & Camel
Technology
What JBoss Fuse can offer
Conclusion
Pattern : Real Time & Broadcasting
Definition : Collect data in real time from different providers (twitter, facebook, …) and broadcast/multicast data to subscribed channels
Business : Event, conference, meeting room
Pattern : Collect Data Metrics/Statistics
Definition : Retrieve data from Social Media and store them in order to query the data to analyze the results
Business : Measure performances of a campaign, product launch, analyze data to design marketing strategies
Pattern : Business Activity Monitoring
Definition : Monitor activities, operational days using reporting, dashboard tools.
Business : Measure performances, rentability, return of investment
Introduction
Social Media Hype
Use cases covered
Integration & Camel
Technology
What JBoss Fuse can offer
Conclusion
|
|
|
OpenSource Java Integration Framework
Designed around : Domain Specific Language
Implement Enterprise Integration Patterns
> 50 patterns implemented
and more : Loadbalancer, Throttler, Delayer, …
|
Key features : route, processor
Interceptor : trace, log, capture business events
|
|
|
|
Data Transformation for complex use case
package org.devnation.camel;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.camel.Exchange;
public interface DataFormat {
void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception;
Object unmarshal(Exchange exchange, InputStream stream) throws Exception;
}Marshalling : Object XML (JAXB)
Unmarshalling : XML Object (JAXB)
Fluent API
package org.devnation.camel;
import org.apache.camel.builder.RouteBuilder;
public class ExampleRouteBuilder extends RouteBuilder {
@Override
public void configure() throws Exception {
from("amq:queue:quotes")
.filter().xpath("/quote/product/ = 'widget")
.bean("QuotesService", "widget")
.filter().xpath("/quote/product/ = 'gadget")
.bean("QuotesService","gadget");
}
}Alternative : Spring, Blueprint DSL
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
">
<bean id="quotesService" class="org.devnation.camel.QuotesService"/>"
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="amq:queue:quotes"/>
<filter>
<xpath>"/quote/product/ = 'widget"</xpath>
</filter>
<bean id="quotesService" method="widget"/>
<filter>
<xpath>"/quote/product/ = 'gadget"</xpath>
</filter>
<bean id="quotesService" method="gadget"/>
</route>
</camelContext>
</beans>In memory bus / alternative to JBI, SCA, NMR
Transport objects : XML, File, Stream, Bytes
Predicate & Expression language (xslt, xpath, …)
Sync/Async exchanges
Threads Management,
Tx Architecture
Error and exception handling
Policy driven
Container agnostic
Introduction
Social Media Hype
Use cases covered
Integration & Camel
Technology
What JBoss Fuse can offer
Conclusion
combined with
camel-gmail
camel-dropbox
camel-ajax, camel-websocket,
camel-sql, camel-jdbc, …
camel-elasticsearch
Open standard for Authorization
OAuth
Component : FaceBook
Grant Access : https://developers.facebook.com/apps
// start with a 30 day window for the first delayed poll
String since = "RAW("
+ new SimpleDateFormat(FACEBOOK_DATE_FORMAT).format(
new Date(System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(30, TimeUnit.DAYS)))
+ ")";
from("facebook://searchPosts?reading.limit=10&" +
"reading.locale=en.US&reading.since=" + since + "&" +
"consumer.initialDelay=1000&" +
"consumer.sendEmptyMessageWhenIdle=true&"
+ getOauthParams());OAuth
protected String getOauthParams() {
return "oAuthAppId=" + properties.get("oAuthAppId") +
"&oAuthAppSecret=" + properties.get("oAuthAppSecret")
+ (properties.get("oAuthAccessToken") != null
? ("&oAuthAccessToken=" + properties.get("oAuthAccessToken")) : "");
}Externalize tokens parameters with Property PlaceHolder
consumer.key=rtPyyyyyyyyyyyyyyyyg
consumer.secret=HyoWW3xxxxxxxxxxxxxxxxTuyEz8qrk
access.token=7976eeeeeeeeeeeeeeeeeeeuRmG0IP
access.token.secret=VNtttttttttttttttttg0B8jWGsExample :
To create a post within your Facebook profile
Send a facebook4j.PostUpdate body to a camel facebook producer
PostUpdate post = new PostUpdate(new URL("http://facebook4j.org"))
.picture(new URL("http://facebook4j.org/images/hero.png"))
.name("Facebook4J - A Java library for " +
"the Facebook Graph API")
.caption("facebook4j.org")
.description("Facebook4J is a Java library" +
" for the Facebook Graph API.");
from("direct:post")
.setBody().constant(post)
.to("facebook://postFeed/inBody=postUpdate");Component Twitter
Grant Access : https://dev.twitter.com/apps/new
Example
from("twitter://search?type=polling&delay="
+ delay + "&useSSL=true&keywords="
+ keywords + "&" + getUriTokens())
.choice()
.when().simple("${body.tweet.text} > 'java'")
.bean("Service", "push")
.otherwise()
.to(">> Tweets received");OAuth
protected String getUriTokens() {
return "consumerKey=" + consumerKey
+ "&consumerSecret=" + consumerSecret
+ "&accessToken=" + accessToken
+ "&accessTokenSecret=" + accessTokenSecret;
}Advanced Query
Simple Example to post a tweet
Date now = new Date();
String tweet = "Demo: this is a tweet posted on " + now.toString();
from("direct:post")
.setBody().constant(tweet)
.to("twitter://timeline/user?" + getUriTokens());Object / JSON
Use utility like Google JSON API
Marshall/Unmmarshall JSON
BAD -
String data = "{ " +
" \"" + "timestamp" + "\" : \"" + formatDate(generateTimeStamp()) + "\"," +
" \"" + "createdAt" + "\" : \"" + status.getCreatedAt().toString() + "\"," +
" \"" + "id" + "\" : \"" + status.getId() + "\"," +
" \"" + "text" + "\" : \"" + status.getText() + '\'' + "\"," +
" \"" + "isFavorited" + "\" : \"" + status.isFavorited() + "\"," +
" \"" + "isRetweeted" + "\" : \"" + status.isRetweeted() + "\"," +
" \"" + "favoriteCount" + "\" : \"" + status.getFavoriteCount() + "\"," +
" \"" + "inReplyToScreenName" + "\" : \"" + status.getInReplyToScreenName() + '\'' + "\"," +
" \"" + "geoLocation" + "\" : \"" + status.getGeoLocation() + "\"," +
" \"" + "place" + "\" : \"" + status.getPlace() + "\"," +
" \"" + "retweetCount" + "\" : \"" + status.getRetweetCount() + "\"," +
" \"" + "isoLanguageCode" + "\" : \"" + status.getIsoLanguageCode() + "\"," +
" \"" + "user" + "\" : \"" + status.getUser().getName() + "\"," +
" \"" + "country" + "\" : \"" + country + "\"" +
" }";BETTER -
private void init(JSONObject json) throws TwitterException {
id = getLong("id", json);
source = getUnescapedString("source", json);
createdAt = getDate("created_at", json);
isTruncated = getBoolean("truncated", json);
inReplyToStatusId = getLong("in_reply_to_status_id", json);
inReplyToUserId = getLong("in_reply_to_user_id", json);
isFavorited = getBoolean("favorited", json);Routing engine Camel & EIP Patterns like |
|
|
Integrated within ActiveMQ & Camel
|
|
Create a bean recuperating Message/Exchange using @Header, @Body
Store it using org.fusesource.insight.storage.StorageService
public class StoreService {
private static String ES_TYPE = "insight-tweet";
private static StorageService storageService;
public static void store(@Header("tweet-full") String data) {
storageService.store(ES_TYPE, generateTimeStamp(), data);
}
public void setStorageService(StorageService storageService) {
StoreService.storageService = storageService;
}Inject Storage service
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
<!-- Service Service used to send tweets to ES Storage, parse JSON -->
<bean id="helper" class="org.devnation.demo.camel.Service">
<property name="storageService">
<reference interface="org.fusesource.insight.storage.StorageService" />
</property>
</bean>
</blueprint>Call it from your Camel route
from("twitter://search?type=polling&delay=" + delay
+ "&useSSL=true&keywords=" + keywords
+ "&" + getUriTokens())
.routeId("Tweet-Store-WS")
.delay(5000)
// We receive the Twitter4J Status that we will use
// to extract info text, isfavorited, is Retweeted, geolocation, isoLanguageCode, contributors
// and create A JSON message used later on to store it in ES
.setHeader("tweet-full").method(Service.class, "getJSONTweet")
// Message is stored using insight in ElasticSearch
.bean(Service.class, "store") Hawtio
Lightweight & modular HTML5 web console with plugins for managing Java MBeans
Javascript / REST front end jolokia JMX translator
Heart of the new Fuse Management Console
Extend Hawtio Dashboard
Declare MBean Interface
public interface SocialMediaMBean {
/* Attributes */
void setTweetsCounter(Integer val);
public Integer getTweetsCounter();
/* Operations */
List<String> searchTweets(String keywords) throws TwitterException;
String userInfo(String id) throws TwitterException;Service Implementation & MBean registration
public List<String> searchTweets(String keywords) throws TwitterException {
return twitterService.searchTweets(keywords);
}
public void init() {
try {
if (objectName == null) {
objectName = new ObjectName("hawtio:type=SocialMedia");
}
if (mBeanServer == null) {
mBeanServer = ManagementFactory.getPlatformMBeanServer();
}
try {
mBeanServer.registerMBean(this, objectName);
} catch (InstanceAlreadyExistsException iaee) {
// Try to remove and re-register
LOG.info("Re-registering SchemaLookup MBean");
mBeanServer.unregisterMBean(objectName);
mBeanServer.registerMBean(this, objectName);
}
} catch (Exception e) {
LOG.warn("Exception during initialization: ", e);
throw new RuntimeException(e);
}
}Inject Service & init beans
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<cm:property-placeholder id="twitterConfig" persistent-id="twitter"
update-strategy="reload"/>
<bean id="twitterFactory" class="org.devnation.demo.service.TwitterFactory">
<property name="consumerKey" value="${consumer.key}"/>
<property name="consumerSecret" value="${consumer.secret}"/>
<property name="accessToken" value="${access.token}"/>
<property name="accessTokenSecret" value="${access.token.Secret}"/>
</bean>
<bean id="twitterService" class="org.devnation.demo.service.TwitterService">
<property name="twitterFactory" ref="twitterFactory"/>
</bean>
<bean id="socialDataMBean" class="org.devnation.demo.service.SocialMedia"
init-method="init" destroy-method="destroy" scope="singleton">
<property name="twitterService" ref="twitterService"/>
</bean>
</blueprint>Create your own hawtio plugin
Web project (war, bundle)
Require to register io.hawt.web.plugin.HawtioPlugin with parameters
Context
JS Scripts location
Name and domain (used by controller)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<bean id="plugin" class="io.hawt.web.plugin.HawtioPlugin" init-method="init" destroy-method="destroy">
<property name="name" value="${plugin-name}"/>
<property name="context" value="${plugin-context}"/>
<property name="domain" value="${plugin-domain}"/>
<property name="scripts" value="${plugin-scripts}"/>
</bean>
</blueprint>
|
$scope.searchTweets = function () {
if (Core.isBlank($scope.keywords)) {
return;
}
jolokia.request({
type: 'exec',
mbean: SOCIAL.mbean,
operation: 'searchTweets',
arguments: [$scope.keywords]
}, {
method: 'POST',
success: function (response) {
/* Simple Table */
$scope.tweets = response.value.map(function (val) {
return { tweet: val };
});
Core.$apply($scope);
},
error: function (response) {
SOCIAL.log.warn("Failed to search for Tweets: ", response.error);
SOCIAL.log.info("Stack trace: ", response.stacktrace);
Core.$apply($scope);
}<div class="row-fluid gridStyle" ng-controller="SOCIAL.FormController">
<h3>Twitter</h3>
<div class="span12">
<div>
<form name="inputForm" ng-submit="searchTweets()">
<div>
Keyword(s) : <input type="text" class="entry-widget" ng-model="keywords">
</div>
<p class="span4 centered">
<input type="submit" class="btn btn-success" ng-disabled="!keywords" value="Search information">
</p>
</form>
</div>
</div>
<div class="span8">
<div class="gridStyle" ng-grid="tweetsGrid"/>
</div>
</div>Introduction
Social Media Hype
Use cases covered
Integration & Camel
Technology
What JBoss Fuse can offer
Conclusion
Introduction
Social Media Hype
Integration & Camel
Use cases covered
Technology
What JBoss Fuse can offer
Conclusion
Fuse Technology ready design Social Media Projects
To cover use cases
Real Time,
Data collection,
Fuse Analytics,
BAM
…
| |
|
Code of demos : https://github.com/cmoulliard/devnation-2014-demos
Social Media Hype
Business - Companies
Marketing Strategy,
Product Promotion,
Launch or Campaign annoucement
Seeking candidates
…
Use Web2.0 but Social Medias